package com.xqkad.myplayer.service;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.MediaMetadata;
import android.media.MediaPlayer;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.provider.MediaStore;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.RemoteViews;

import com.xqkad.myplayer.MainApplication;
import com.xqkad.myplayer.MediaAidlInterface;
import com.xqkad.myplayer.R;
import com.xqkad.myplayer.info.MusicInfo;
import com.xqkad.myplayer.utils.PreferencesUtility;

import java.util.ArrayList;
import java.util.List;

public class MediaService extends BroadcastService {
    private MediaPlayer mPlayer,mNextPlayer;
    private HandlerThread handlerThread;
    private Handler handler;
    private List<MusicInfo> mPlayList = new ArrayList<MusicInfo>();
    private int mPos = -1;
    private int mPlayMode = 0;//0, 1, 2//
    private Notification mNotification;
    private MediaSession mSession;
    interface Consts {
        String SELF = "self";
        String NOTIFICATION_CHANNEL_ID = "1";
    }


    private void startNotification(){
        Intent intent = new Intent(this,MediaService.class);
        intent.setAction(Consts.SELF);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(intent);
        }else {
            startService(intent);
        }
    }
    private void createNotification(){
        RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.notification);;
        final int PAUSE_FLAG = 0x1;
        final int NEXT_FLAG = 0x2;
        final int STOP_FLAG = 0x3;
        final String albumName = "";
        final String artistName = "";
        final boolean isPlaying = isPlaying();

        remoteViews.setImageViewResource(R.id.imageView, R.drawable.music);
        remoteViews.setTextViewText(R.id.title, ""+getTitle());
        remoteViews.setTextViewText(R.id.text, "");

        Intent pauseIntent = new Intent(Actions.TO_TOGGLE_PLAY_PAUSE);
        pauseIntent.putExtra("FLAG", PAUSE_FLAG);
        PendingIntent pausePIntent = PendingIntent.getBroadcast(this, 0, pauseIntent, 0);
        remoteViews.setImageViewResource(R.id.iv_pause, isPlaying ? R.drawable.note_btn_pause : R.drawable.note_btn_play);
        remoteViews.setOnClickPendingIntent(R.id.iv_pause, pausePIntent);

        Intent nextIntent = new Intent(Actions.TO_NEXT);
        nextIntent.putExtra("FLAG", NEXT_FLAG);
        PendingIntent nextPIntent = PendingIntent.getBroadcast(this, 0, nextIntent, 0);
        remoteViews.setOnClickPendingIntent(R.id.iv_next, nextPIntent);

        Intent preIntent = new Intent(Actions.TO_STOP);
        preIntent.putExtra("FLAG", STOP_FLAG);
        PendingIntent prePIntent = PendingIntent.getBroadcast(this, 0, preIntent, 0);
        remoteViews.setOnClickPendingIntent(R.id.iv_stop, prePIntent);

        final Intent nowPlayingIntent = new Intent();
        //nowPlayingIntent.setAction("com.wm.remusic.LAUNCH_NOW_PLAYING_ACTION");
        nowPlayingIntent.setComponent(new ComponentName("com.xqkad.myplayer","com.xqkad.myplayer.activity.PlayingActivity"));
        nowPlayingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent clickIntent = PendingIntent.getBroadcast(this, 0, nowPlayingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        PendingIntent click = PendingIntent.getActivity(this,0,nowPlayingIntent,PendingIntent.FLAG_UPDATE_CURRENT);

        if(mNotification == null){
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                    .setSmallIcon(R.drawable.music)
                    .setContent(remoteViews)
                    .setContentIntent(click)
                    .setShowWhen(false)
                    .setWhen(System.currentTimeMillis());  //设置时间
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
                NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                NotificationChannel channel = new NotificationChannel(Consts.NOTIFICATION_CHANNEL_ID,"name",NotificationManager.IMPORTANCE_LOW);
                nm.createNotificationChannel(channel);
                builder.setChannelId(Consts.NOTIFICATION_CHANNEL_ID);
            }
            mNotification = builder.build();
        }else{
            mNotification.contentView = remoteViews;
        }
        startForeground(1000,mNotification);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        init();
        mPlayMode = 2;
        //sendBroad
    }
    void init(){
        //Log.d(TAG, "init: "+Thread.currentThread().getName());
        mSession = new MediaSession(this,"myplayer");
        mSession.setCallback(new MediaSession.Callback() {
            @Override
            public void onPause() {
                Log.d(TAG, "ses: pause");
            }

            @Override
            public void onPlay() {
                Log.d(TAG, "ses: play");
            }
        });
        mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);

        handlerThread = new HandlerThread("handlerThread");
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
    }
    @Override
    public IBinder onBind(Intent intent) {
        super.onBind(intent);
        return new ServiceStub(this);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if(intent != null && Consts.SELF.equals(intent.getAction())){
            createNotification();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        super.onUnbind(intent);
        return true;
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)
            handlerThread.quitSafely();
        else handlerThread.quit();
        mSession.release();
    }

    @Override
    protected boolean isPlaying(){
        return mPlayer != null && mPlayer.isPlaying();
    }
    @Override
    protected void togglePlayPause() {
        super.togglePlayPause();
    }
    @Override
    protected void play() {
        doInBack(new Runnable() {
            @Override
            public void run() {
                synchronized (MediaService.this){
                    playImpl();
                }
            }
        });
    }
    @Override
    protected void pause() {
        doInBack(new Runnable() {
            @Override
            public void run() {
                synchronized (MediaService.this){
                    pauseImpl();
                }
            }
        });
    }
    @Override
    protected void previous() {
        doInBack(new Runnable() {
            @Override
            public void run() {
                synchronized (MediaService.this){
                    previousImpl();
                }
            }
        });
    }
    @Override
    protected void next() {
        doInBack(new Runnable() {
            @Override
            public void run() {
                synchronized (MediaService.this){
                    nextImpl();
                }
            }
        });
    }
    @Override
    protected void stop() {
        doInBack(new Runnable() {
            @Override
            public void run() {
                synchronized (MediaService.this){
                    stopImpl(true);
                }
            }
        });
    }
    protected void setPlayMode(int mode){
        mPlayMode = mode;
        super.setPlayMode();
    }

    ////impl////

    private void playImpl(){
        //Log.d(TAG, "play: "+gtn());
        if(mPlayList.size()==0){
            return;
        }
        if(mPlayer != null && !mPlayer.isPlaying()){
            mSession.setActive(true);
            mPlayer.start();
            updateSession();
            startNotification();
            super.play();
        }
    }

    private void pauseImpl(){
        if(mPlayer != null && mPlayer.isPlaying()){
            mPlayer.pause();
        }
        startNotification();
        super.pause();
    }

    private void previousImpl(){
        if(mPlayList.size() == 0){
            return;
        }

        stopImpl(false);
        if(mPos == 0) {
            mPos = mPlayList.size() - 1;
        }else{
            mPos--;
        }
        setDataAndCallback();
        super.previous();
    }

    private void nextImpl(){
        //Log.d(TAG, "next: "+gtn());
        if(mPlayList.size() == 0)
            return;

        stopImpl(false);
        if(mPos + 1 < mPlayList.size()) {
            mPos++;
        }else if(mPos + 1 == mPlayList.size()){
            mPos = 0;
        }
        setDataAndCallback();
        super.next();
    }

    private void stopImpl(boolean stopNotification){
        if(mPlayer == null) return;
        try{
            mSession.setActive(false);
            mPlayer.stop();
            mPlayer.release();
            mPlayer = null;
            //mPlayList.clear();
            if(stopNotification){
                stopForeground(true);
            }
            super.stop();
        }catch (Exception e){}
    }

    private void open(List<MusicInfo> list, int position){
        stopImpl(false);
        mPlayList = list;
        mPos = position;
        setDataAndCallback();
    }

    private void setDataAndCallback(){
        //Log.d(TAG, "setDataAndCallback: "+mPos+" "+gtn());
        Uri uri;
        if(mPlayList.get(mPos).isNet){
            String data = mPlayList.get(mPos).data;
            uri = Uri.parse("https://res.wx.qq.com/voice/getvoice?mediaid="+data);
        }else{
            String id = mPlayList.get(mPos).id;
            uri = Uri.parse(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI+"/"+id);
        }

        try {
            mPlayer = new MediaPlayer();
            mPlayer.setDataSource(MainApplication.context,uri);
            mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    if(mPlayList.get(mPos).duration == 0){
                        mPlayList.get(mPos).duration = mPlayer.getDuration();
                    }
                    play();
                }
            });
            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    //Log.d(TAG, "onCompletion: "+mPos+"/"+mPlayList.size());
                    if(mPlayMode == 0)
                        next();
                    if(mPlayMode == 1)
                        mPlayer.seekTo(0);
                    if(mPlayMode == 2)
                        pause();
                }
            });
            mPlayer.prepareAsync();
        } catch (Exception e) {}
    }

    private void seek(final int position){
        if(mPlayer != null && mPlayList.size() != 0){
            mPlayer.seekTo(position);
        }
    }

    private int getDuration(){
        if(mPlayer != null && mPlayList.size() != 0)
            return mPlayList.get(mPos).duration;
        return -1;
    }

    private int getCurrentPosition(){
        if(mPlayer != null)
            return mPlayer.getCurrentPosition();
        return -1;
    }

    private int getPosition(){
        if(mPlayer != null && mPlayList.size() != 0)
            return mPos;
        return -1;
    }

    private String getTitle(){
        if(mPlayer != null && mPlayList.size() != 0 && mPos != -1)
            return mPlayList.get(mPos).title;
        return "无";
    }

    private String getMusicId(){
        if(mPlayer != null && mPlayList.size() != 0 && mPos != -1)
            return mPlayList.get(mPos).id;
        return "-1";
    }

    private int getPlayMode(){
        return mPlayMode;
    }

    private void updateSession(){
        int playState = isPlaying()
                ? PlaybackState.STATE_PLAYING
                : PlaybackState.STATE_PAUSED;

        mSession.setMetadata(new MediaMetadata.Builder()
                .putString(MediaMetadata.METADATA_KEY_ARTIST, "artist")
                .putString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST, "album_artist")
                .putString(MediaMetadata.METADATA_KEY_ALBUM, "album")
                .putString(MediaMetadata.METADATA_KEY_TITLE, getTitle())
                .putLong(MediaMetadata.METADATA_KEY_DURATION, getCurrentPosition())
                .putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, mPos)
                .putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, 4)
                .putString(MediaMetadata.METADATA_KEY_GENRE, "genreName")
                .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null)
                .build());

        mSession.setPlaybackState(new PlaybackState.Builder()
        .setState(playState, getCurrentPosition(), 1.0f)
        .setActions(PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY_PAUSE |
                PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS)
        .build());
    }

    private void doInBack(Runnable runn){
        if(Looper.myLooper() == Looper.getMainLooper()){
            handler.post(runn);
        }else{
            runn.run();
        }
    }

    private static class ServiceStub extends MediaAidlInterface.Stub {
        private final MediaService mService;

        public ServiceStub(MediaService service){
            mService = service;
        }

        @Override
        public void open(List infos, int position) throws RemoteException {
            mService.open(infos,position);
        }

        @Override
        public void play() throws RemoteException {
            mService.play();
            //Log.d(TAG, Thread.currentThread().getName()+" play: stub");
        }

        @Override
        public void pause() throws RemoteException {
            mService.pause();
        }

        @Override
        public void previous() throws RemoteException {
            mService.previous();//Log.d(TAG, Thread.currentThread().getName()+" play: stub");
        }

        @Override
        public void next() throws RemoteException {
            mService.next();
        }

        @Override
        public void stop() throws RemoteException {
            mService.stop();
        }

        @Override
        public void seek(final int position) throws RemoteException {
            mService.seek(position);
        }

        @Override
        public boolean isPlaying() throws RemoteException{
            return mService.isPlaying();
        }

        @Override
        public int getDuration() throws RemoteException{
            return mService.getDuration();
        }

        @Override
        public int getCurrentPosition() throws RemoteException{
            return mService.getCurrentPosition();
        }

        @Override
        public int getPosition() throws RemoteException{
            return mService.getPosition();
        }

        @Override
        public String getTitle() throws RemoteException{
            return mService.getTitle();
        }

        @Override
        public String getMusicId() throws RemoteException{
            return mService.getMusicId();
        }

        @Override
        public int getPlayMode() throws RemoteException{
            return mService.getPlayMode();
        }

        @Override
        public void setPlayMode(int mode) throws RemoteException{
            mService.setPlayMode(mode);
        }
    }
}
